/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019.
 * Description: support some function of irq-group
 * Author: xiaojiangfeng <xiaojiangfeng@huawei.com>
 * Create: 2018-11-22
 */

#define NON_SECURE_INT                  (1 << 1)
#define SECURE_INT                      (1 << 0)
#define GIC_ICCICR_EnableS              (1 << 0)
#define GIC_ICCICR_EnableNS             (1 << 1)
#define GIC_ICCICR_AckCtl               (1 << 2)
#define GIC_ICCICR_FIQEn                (1 << 3)
#define GIC_ICCICR_SBPR                 (1 << 4)
#define GIC_ICDICTR_SECURITY            (1 << 10)
#define GIC_ICDSGIR_SATT                (1 << 15)
#define GIC_ICDSGIR_SATT_CORE16		(1 << 7)

/* GIC security group0 */
#define GIC_SECURITY_GROUP      (0)
/* GIC nonsecurity group1 */
#define GIC_NONSECURITY_GROUP   (1)
static unsigned int gic_irq_group = GIC_SECURITY_GROUP;

#ifdef	CONFIG_FIQ_GLUE
unsigned int ipi_to_fiq;
/* some GIC do not support N2N irq, set ipi0 to fiq; because ipi has N2N feature. */
#define IPI0_TO_FIQ             (1)
/* set ipi0 to normal irq */
#define IPI0_TO_IRQ             (0)
#endif

void gic_irq_group_get(struct device_node *node, void __iomem *dist_base)
{
	u32 reg_val;

	/* check gic nosecurity support */
	reg_val = readl_relaxed(dist_base + GIC_DIST_CTR);
	if (reg_val & GIC_ICDICTR_SECURITY) {
		if (of_property_read_u32(node, "irq_group", &gic_irq_group)) {
			printk(KERN_WARNING"Can't find irq_group in dtb.\n");
			gic_irq_group = GIC_SECURITY_GROUP;
		}
	} else {
		printk(KERN_INFO "[%s]gic dose't support nonsecurity irq.\n", __func__);
		gic_irq_group = GIC_SECURITY_GROUP;
	}

#ifdef CONFIG_FIQ_GLUE
	if (gic_irq_group == GIC_NONSECURITY_GROUP) {
		if (of_property_read_u32(node, "ipi0_to_fiq", &ipi_to_fiq)) {
			printk(KERN_WARNING"Can't find ipi0_to_fiq in dtb, set ipi0 as normal irq.\n");
			ipi_to_fiq = IPI0_TO_IRQ;
		}
	}
#endif
}


void gic_dist_nosec_set(void __iomem *dist_base)
{
	if (gic_irq_group != GIC_NONSECURITY_GROUP)
		return;

	writel_relaxed(NON_SECURE_INT | SECURE_INT, dist_base + GIC_DIST_CTRL);
}

void gic_cpu_nosec_set(void __iomem *dist_base, void __iomem *cpu_base, u32 irq_nr)
{
	int i;

	writel_relaxed(0x2, cpu_base  + GIC_CPU_BINPOINT);

	if (gic_irq_group != GIC_NONSECURITY_GROUP)
		return;

	/* banked IPIs,PPIs */
#ifdef CONFIG_FIQ_GLUE
	if (ipi_to_fiq == IPI0_TO_FIQ) {
		unsigned int val;
		/* set ipi0 to group0 when enable ipi0 to fiq. */
		writel_relaxed(0xfffffffe, dist_base  + GIC_DIST_IGROUP);
		/* set priority of irq 0 to 0 */
		val = readl_relaxed(dist_base  + GIC_DIST_PRI);
		val &= 0xffffff00;
		writel_relaxed(val, dist_base  + GIC_DIST_PRI);
	} else {
		writel_relaxed(0xffffffff, dist_base  + GIC_DIST_IGROUP);
	}
#else
	writel_relaxed(0xffffffff, dist_base  + GIC_DIST_IGROUP);
#endif

	/* N2N irq is percpu banked */
	for (i = 32; i <= irq_nr; i += 32)
		writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + (i / 32) * 4);

	writel_relaxed(GIC_ICCICR_EnableS | GIC_ICCICR_EnableNS
			| GIC_ICCICR_AckCtl | GIC_ICCICR_SBPR
			| GIC_ICCICR_FIQEn,
			cpu_base + GIC_CPU_CTRL);
}

int sgi_satt_flag(int core)
{
	if (gic_irq_group != GIC_NONSECURITY_GROUP)
		return 0;

	if (core == 16)
		return GIC_ICDSGIR_SATT_CORE16;

	return GIC_ICDSGIR_SATT;
}
